package Concurrency3_Art.chapter01;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 功能说明：
 * <<Java并发编程艺术>>一书, 后面都简称"艺术"
 * 艺术一书中, 验证并行程序与串行程序的执行效率的案例, 不太恰当:
 * 1, 并发程序采用的一个线程, 串行程序不比说肯定也是一个线程, 这样的话, 并行程序永远不应该比串行程序快.
 * 2, 更恰当的做法, 应该是多线程分配好任务之后, 与串行程序做对比
 * ----------------------------新案例设计----------------------------------
 * 1, 测试用例: {10, 100, 1000, 10000, 100000, 1000000, 10000000}
 * 2, 多线程: 线程数10个, 每个线程分段计数, 然后合并
 * 3, 串行程序: 一个线程进行计算
 * <p>
 *     还是不够恰当, 理论上应该使用forkjoin框架
 * ----------------------------新案例设计----------------------------------
 * 开发人员：@author MaLi
 */
public class T01_CheckContextSwitch {
    private static long[] numbers = {10000000,100000000,1000000000};

    //多线程分段计数
    public static void main(String[] args) {
        for (long number : numbers) {
            concurrentCount(number);
            serialCount(number);
        }
    }

    private static void serialCount(long number) {
        AtomicLong result = new AtomicLong(0);
        //串行计数
        long begin = System.currentTimeMillis();
        for (long i = 0; i < number; i++) {
            result.getAndAdd(i);
        }
        long end = System.currentTimeMillis();
        System.err.println("串行计数结果:" + result.get() + " --- 执行时间: " + (end - begin));
    }

    private static AtomicLong concurrentCount(long number) {
        // 创建10个线程
        List<Thread> threads = new ArrayList<>();
        //每个线程执行一个区间段的计数
        long stage = number / 10;
        // 结果容器
        AtomicLong result = new AtomicLong();
        long begin = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            long start = i * stage;
            long end = start + stage;
            threads.add(new Thread(() -> {
                // 计数区间
                // stage = number/10   init=i*stage end = init+stage
                for (long j = start; j < end; j++) {
                    result.getAndAdd(j);
                }
            }));
        }
        for (Thread thread : threads) {
            thread.start();
        }
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("并行计数结果:" + result.get() + " --- 执行时间: " + (end - begin));
        return result;
    }
}
